#! /usr/bin/env ruby

require_relative './test_config'
require 'pathname'
require 'typelib'
require 'rexml/document'

# Tests should not require any include paths except the test directory itself
# (which is automatically added). Defines can be passed with -DXXXX[=YYYY]
#
# The C++ input file must have a .hh extension
#
# If opaques are needed, they should be placed in the test directory and named
# "basename.opaques" (where 'basename' is the name of the C++ input file without
# its extension)
#
# The generated tlb is output as basename.tlb.new. REVIEW IT before renaming it
# to .tlb (as expected by the tests)

defines = Array.new
argv = ARGV.find_all do |arg|
    if arg =~ /^-D(.*)/
        defines << $1
        false
    else true
    end
end

if argv.size != 1
    raise ArgumentError, "expected only one input file, got #{argv.inspect}"
end

cxx_test_dir = File.join(SRCDIR, 'ruby', 'cxx_import_tests')
cxx_file     = File.join(cxx_test_dir, argv.first)
if File.extname(cxx_file) != ".hh"
    raise ArgumentError, "expected the input C++ file to end with .hh"
elsif !File.file?(cxx_file)
    raise ArgumentError, "expected file #{cxx_file} does not exist"
end

prefix       = File.join(cxx_test_dir, File.basename(cxx_file, ".hh"))
opaques_file = "#{prefix}.opaques"

registry = Typelib::Registry.new
if File.file?(opaques_file)
    registry.merge_xml(File.read(opaques_file))
end
registry.import(cxx_file, 'c', cxx_importer: 'castxml', defines: defines, include_paths: [cxx_test_dir])

# Format the source_file_line metadata since it can really not be ported across
# compilers and filesystems
#
# The only source_file_line properties we try to keep are the ones that point to
# files within the test directory
def filter_metadata(metadata, test_dir)
    source_file_line = metadata.get('source_file_line').first
    if source_file_line
        if source_file_line.start_with?(test_dir)
            source_file_line = Pathname.new(source_file_line).relative_path_from(Pathname.new(test_dir)).to_s
            metadata.set('source_file_line', source_file_line)
        else
            metadata.delete('source_file_line')
        end
    end
end

registry.each do |type|
    filter_metadata(type.metadata, cxx_test_dir)
    if type.respond_to?(:each_field)
        type.each_field do |name, _|
            filter_metadata(type.field_metadata[name], cxx_test_dir)
        end
    end
end

# The formatting generated by the TLB importer is broken ... Fixing it would be
# a nice to have, but is not a big deal in general since noone is meant to edit
# tlb files by hand
#
# However, we're in the case where formatting matters (the XML files are meant
# to be reviewed manually), use REXML to reformat.
new_tlb = File.join(cxx_test_dir, "#{File.basename(cxx_file, '.hh')}.tlb.new")
File.open(new_tlb, 'w') do |io|
    REXML::Document.new(registry.to_xml).write(io, 4)
end
puts "written: #{new_tlb}"
